<?php
// +----------------------------------------------------------------------
// |  帐户控制器
// +----------------------------------------------------------------------
namespace app\appadmin\controller\soft;
use app\app\Appbase;
use \Firebase\JWT\JWT;
use think\facade\Cache;
use lib\wechat\Wechat;
use base\service\MsgApi;
use app\app\controller\soft\Auth as AppAuth;

class Auth extends Appbase
{
	private $name = 'shop_staff';   										// 用户表名-全称
	private $key = 'id';		 												// 用户guid
	private $code_field = 'code'; 										// 登录账号字段
	private $pwd_field = 'password';									// 登录密码字段
	private $strKey = 'Mhc(jk`[t.7?P_Ty=A%417+S{J390DKpFmvW@E}';  //密钥
	private $accessTokenExpirationTime = 3600;				//accessToken过期时间(秒)
   	private $refreshTokenExpirationTime = 86400 * 5;		//refreshToken过期时间(秒)
	
	
	//-----
	//公众号
	//-----
	private $webConfig;  	
	private $appid;         
	private $appsecret;     
	private $redirect_uri;
	private $success_uri;  	
	private $scope='snsapi_userinfo';  	//snsapi_userinfo , snsapi_base
	
	// 用户信息关联表
	private $withs = [];
	
	//身份
	private $identity = 3;		
	
	//会在new的时候自动执行
	public function __construct() {
		parent::__construct();
		
		//微信配置
		$this->webConfig = $webConfig = env('system_base_config_wx_web'); 
		$this->redirect_uri = APP_PATH.'/index.php/appadmin/soft/auth/getWxUserInfo';
		$this->success_uri = APP_PATH.'h5Manage/index.html#/';
		$this->appid = $webConfig['appid'];
        $this->appsecret = $webConfig['appsecret'];
        
        
		// 用户信息关联表
		$this->withs = ['shopInfo'];	
		$this->withs = [];	
		
		$code = input('code');
		if( $code == 'admin' || mb_strlen($code) == 11 ){
			$this->name = 'system_user';   				
			$this->key = 'user_guid';   					
			$this->code_field = 'user_code';   					
			$this->pwd_field = 'user_pwd';   					
		}
		if($code == 'admin'){ $this->identity = 1; }
		if( mb_strlen($code)==11 ){ $this->identity = 2; }
    }
	
	
	/**
     * 绑定微信
	 * /appadmin/soft/auth/wxBinding
	 * @is_need_login false
    */
	public function wxBinding($wxInfo=[]){
	    if(!$this->webConfig){
            echo "微信公众号配置信息错误，请联系后台管理员！";
            die;
        }  
        $id = request()->get('id','');  $path = urldecode(request()->get('path',''));
		if( empty($wxInfo) ){
			$weObj = new Wechat( $this->webConfig );
			$url = $this->redirect_uri.'?id='.$id.'&path='.urlencode($path);
			$url =  $weObj->getOauthRedirect($url,'',$this->scope);
			$this->redirect($url, 302);// tp5的重定向方法 
		}else{
			$wxInfo['remark'] = 'wx-web';
			$result = (new AppAuth)->wxLogin($wxInfo);
			if(!$result)	return $this->ReError();
			$res = model('ShopStaff')->bindingMember($id,$result['id']);
			$token = 'code='.( $res ? 1 : 0);
			//绑定成功-跳转到对应网页
			if($path){
				$url = $path.( strstr($path,"?") ? '&' : '?' ).$token;
			}else{
				$url = $this->success_uri. '?'.$token;
			}
	        $this->redirect($url, 302);// tp5的重定向方法 
		}
	}
	
	/**
     * 获得wxkey
	 * /appadmin/soft/auth/getWxKey
	 * @is_need_login false
    */
	public function getWxKey($wxInfo=[]){
		$path = urldecode(request()->get('path',''));
		if(!$path){
            echo "缺少path参数！";
            die;
        }  
	    if(!$this->webConfig){
            echo "微信公众号配置信息错误，请联系后台管理员！";
            die;
        }  
		if( empty($wxInfo) ){
			$weObj = new Wechat( $this->webConfig );
			$url = $this->redirect_uri.'?path='.urlencode($path);
			$url =  $weObj->getOauthRedirect($url,'',$this->scope);
			$this->redirect($url, 302);// tp5的重定向方法 
		}else{
			$wxInfo['remark'] = 'wx-web';
			$key =  md5( json_encode($wxInfo,true) );
			Cache::set('cache_wx_info_'.$key,$wxInfo,5000);
			$token = 'key='.$key;
	        $this->redirect( $path.( strstr($path,"?") ? '&' : '?' ).$token , 302);// tp5的重定向方法 
		}
	}
	
	
	/**
    * 微信用户信息
	* /appadmin/soft/auth/getWxUserInfo
	* @is_need_login false
	* 
    */
	public function getWxUserInfo()
	{
		$weObj = new Wechat( $this->webConfig );
		$result = $weObj->getOauthAccessToken();
		$wxUserinfo = Cache::get('wx_oauth_userinfo'.request()->get('code'));
		if(!$result && $wxUserinfo){
			$this->getWxUserInfo( $wxUserinfo );
			return true;
		}
		if($result && $result['scope'] != 'snsapi_base'){
			$result = $weObj->getOauthUserinfo($result['access_token'],$result['openid']);
			if($result){
				Cache::set('wx_oauth_userinfo'.request()->get('code'),$result,360);
			}
		}
		if(!$result){
			echo "授权错误！".'</br>';
        	echo 'errcode：'.$weObj->errCode.'</br>';
        	echo 'errmsg ：'.$weObj->errMsg.'</br>';
            die;
		}
		$this->getWxKey( $result );
	}
	
	
	
	/**
     * 登录
	 * /app/soft/auth/login
	 * @is_need_login false
	 * @access public
     * @param string $user_name   	用户名称
     * @param string $user_pwd 		用户密码
     * @return json
    */
    public function login($code,$pwd,$key)
    {
    	if(!$code || !$pwd || !$key){
			return $this->ReError("请求参数错误！");
		}
		
		if( !$wxInfo = Cache::get('cache_wx_info_'.$key) ){
//			return $this->ReError("key参数错误或已过期,请退出重新进入！");
		}
		
		if( $this->identity == 1 ){
			$userInfo = model('admin/'.$this->name )
				->where($this->code_field ,"$code")
				->where($this->pwd_field , md5('wei'.md5($pwd)) )
				->field($this->login_pwd_field ,true)
				->find();
			if( empty($userInfo) == true ){
				return  $this->ReError('账号和密码不符');
			}
			if( $userInfo['is_enable'] == "0" ){
				return  $this->ReError('该账户已被禁用');
			}		
		}
		
		if( $this->identity == 2 ){
			$vipInfo = model('user_vip')->alias('a')
				->leftJoin("xw_shop b",'b.uid = a.uid')
				->where('a.phone' ,$code)
				->where('a.password', md5($pwd) )
				->where('b.is_del',0)
				->whereNotNull('b.id')
				->where('b.is_enable',1)
				->field('a.*,b.id as shop_id,b.name as shop_name,b.is_enable')
				->find();
			if( empty($vipInfo) == true ){
				return  $this->ReError('账号和密码不符');
			}
			if( $vipInfo['is_enable'] == "0" ){
				return  $this->ReError('该账户已被禁用');
			}	
			$res = model('admin/'.$this->name )->where( 'user_code', $vipInfo['phone'] )->find();
			if( empty($res) == true ){
				model( $this->name )->insert([
					'user_guid' => get_uuid(),
				 	'user_name' => $vipInfo['shop_name'],
				 	'user_code' => $vipInfo['phone'],
				 	'shop_id' => $vipInfo['shop_id'],
				 	'uid' => $vipInfo['uid'],
				 	'org_id'  => 2,
				 	'is_admin' => 0
				]);
			}
			$userInfo = model('admin/'.$this->name)->where('user_code',$vipInfo['phone'])->find();
		}
		
		if( $this->identity == 3 ){
			$map[$this->code_field] = $code;
			$map[$this->pwd_field] =  $pwd;  //md5($pwd);
			$userInfo = model($this->name)->where($map)->field($this->pwd_field,true)->find();
			if( $userInfo == null ){
				return  $this->ReError('账号和密码不符');
			}
			if( $userInfo['is_del'] == "1" ){
				return  $this->ReError('该账户已被禁用');
			}
			if( $userInfo['status'] == "0" ){
				return  $this->ReError('已离职！');
			}
			if(!$userInfo->uid){
				if( !$result = (new AppAuth)->wxLogin($wxInfo) ){
					return $this->ReError("绑定微信用户失败！");
				}
				$userInfo->uid = $result['id'];
				$userInfo->save();
			}
			$user['is_bind_wx'] = $userInfo['uid'] ? 1 : 0; 
		}
		
		$user['id'] = $userInfo['id'] ?? $userInfo['user_id'] ?? '';
		$user['user_id'] = $userInfo['id'] ?? $userInfo['user_id'] ?? '';
		$user['user_guid'] = $userInfo['user_guid'] ?? '';
		$user['shop_id'] = $userInfo['shop_id'];
		$user['name'] = $userInfo['name'] ?? $userInfo['user_name'] ?? '';
		$user['identity'] = $this->identity;
		$user['is_bind_wx'] = $user['is_bind_wx'] ?? 0; 
		$user['wx_info'] = $wxInfo;
		
		return $this->ReSucess($this->results($user),"登录成功!");
    }
	
	
	/**
    * 退出
	* /app/soft/auth/logout
	* @is_need_login true
    * @return boolean
    */
    public function logout()
    {
    	Cache::set('user_token_'.request()->identity.'_'.request()->userId,0);
        return  json(array("code"=>0,"data"=>"","msg"=>"退出成功"));
    }
	
	/**
     * 获取用户信息
	 * /app/soft/auth/getUserInfo
	 * @is_need_login true
     * @return boolean
     */
    public function getUserInfo($token)
    {
    	if( empty($token) == true ){
			throw new \think\Exception( "accessToken必填！" );
		}
		
        $result = $this->verifyToken($token);
	    if( !empty($result['error'])  ){
	   		return $result;
	    }
	    
		if(!$userInfo = $result['jwt']['userinfo']){
			return false;
		}
		
		if(!Cache::get('user_token_'.$userInfo['identity'].'_'.($userInfo['id'] ?? 0))){
			return false;
		}
		
		if( $userInfo['identity'] !=3 ){
			$result['info'] = model('admin/system_user' )
				->where('user_guid', $userInfo['user_guid'] )
				->field('user_pwd',true)
				->find();
		}else{
			$result['info'] = model( $this->name )
				->where($this->key, $userInfo[$this->key] )
				->field($this->pwd_field,true)
				->find();
		}
		
		$result['info']['is_bind_wx'] = $userInfo['is_bind_wx'];
		$result['info']['identity'] = $userInfo['identity'];
		$result['info']['wx_info'] = $userInfo['wx_info'];
		
	    return $result;
    }
	
	
	/**
    * 创建accessToken
	* @is_need_login false
    * @param string $userInfo  用户信息
    * @param string $type  类型：  'access' 、'refresh'
    * @return josn token
    */
	public function getAccessToken($userId){
		return $this->createToken($userId,$this->accessTokenExpirationTime,'access');
	}
	
	/**
    * 创建刷新Token
	* @is_need_login false
    * @param string $userId  用户id
    * @return josn token
    */
	public function getRefreshToken($userId){
		return $this->createToken($userId,$this->refreshTokenExpirationTime,'refresh');
	}
	
	/**
     * 创建Token函数
	 * @is_need_login false
     * @param string/array  $info  额外信息
     * @return josn token
    */
    public function createToken($info,$exp,$type) {
        $token = [
            "iss"=>"",  	//签发者 可以为空
            "sub"=>"",    //jwt所面向的用户，可以为空
            "aud"=>"", 	//接收jwt的一方
            "iat" => time(), 		//签发时间
            "nbf" => time(), 		//在什么时候jwt开始生效 
            "exp" => time() + $exp, //token 过期时间
            "jti" => 1, 		//jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。
            "token_type"=> $type,
        ];
		$token['userinfo'] = $info;
        return  JWT::encode($token,$this->strKey,"HS256"); //根据参数生成了 token
    }
	
	/**
     * 刷新token
	 * /app/soft/auth/refreshToken
	 * @is_need_login false
	 * @access public
     * @param string $refresh_token  刷新token
     * @return json
    */
	public function refreshToken(){
		
		$refresh_token = request()->post("refresh_token");
	 	if( empty($refresh_token) ){
			return  json(array("code"=>-10,"data"=>"","msg"=>"未找到refresh_token！"));
	 	}
		
		$userInfo = $this->getUserInfo($refresh_token);
		if( !empty($userInfo['error']) ){
			return  json(array("code"=>-10,"data"=>"","msg"=>"token过期，请重新登录！"));
		}
		
		if( $userInfo['jwt']['token_type'] != 'refresh'){
			return  json(array("code"=>-10,"data"=>"","msg"=>"token类型错误！"));
		}
		
		return $this->ReSucess($this->results($userInfo['info']),"token成功刷新!");
	} 
	
	/**
     * jws校验token
     *@is_need_login false
     * @param token
     * @return 返回 用户id
     * @throws JoseException
     */
    private function verifyToken($token) {
    	$result = ["error"=>"","jwt"=>""];
		try {
			$result["jwt"] =  JWT::decode($token,$this->strKey,["HS256"]) ;//解密jwt
			$result["jwt"] =  json_decode(json_encode($result["jwt"]) ,true);
		}catch (\Exception $e) {
            $result['error'] =  $e->getMessage();
        }
		return $result;
    } 
	
	/**
     * 返回接口
	 * /app/soft/login/refreshToken
	 * @access public
     * @param string $refresh_token  刷新token
     * @return json
    */
	public function results($userInfo){
		unset($userInfo['openid']);
		unset($userInfo['unionid']);
		Cache::set('user_token_'.$userInfo['identity'].'_'.($userInfo['id'] ?? 0),true);
		$result = [
			"access_token" => $this->getAccessToken($userInfo),
			"refresh_token" => $this->getRefreshToken($userInfo),
			"userinfo" => $userInfo
		];
		unset($userInfo['wx_info']);
		$result['userinfo'] = $userInfo;
		return $result;
	}
	
}
